<!DOCTYPE html>
<html>

<head>
    <title>Image Annotation Tool</title>
    <style>
        body {
            width: 400px;
            padding: 15px;
            font-family: Arial, sans-serif;
            margin: 0 auto;
        }

        .container {
            display: flex;
            flex-direction: column;
            gap: 10px;
        }

        h2 {
            margin: 0 0 15px 0;
            text-align: center;
            color: #333;
        }

        .input-group {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .input-group label {
            width: 120px;
            font-size: 14px;
        }

        .input-group input[type="file"] {
            flex-grow: 1;
            font-size: 14px;
        }

        .input-group input[type="number"] {
            width: 60px;
            padding: 5px;
        }

        button {
            padding: 8px 12px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }

        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }

        button:hover:not(:disabled) {
            background-color: #45a049;
        }

        .canvas-container {
            margin-top: 15px;
            border: 1px solid #ddd;
            padding: 5px;
            text-align: center;
        }

        canvas {
            max-width: 100%;
            max-height: 300px;
            display: none;
        }
    </style>
</head>

<body>
    <div class="container">
        <h2>Image Annotation Tool</h2>

        <div class="input-group">
            <label for="imageInput">选择图片:</label>
            <input type="file" id="imageInput" accept="image/*">
        </div>

        <div class="input-group">
            <label for="jsonInput">选择JSON文件:</label>
            <input type="file" id="jsonInput" accept=".json">
        </div>

        <div class="input-group">
            <label for="widthInput">目标宽度(px):</label>
            <input type="number" id="widthInput" value="1024" min="100">
        </div>

        <div class="input-group">
            <label for="heightInput">目标高度(px):</label>
            <input type="number" id="heightInput" value="1366" min="100">
        </div>

        <button id="processBtn" disabled>标注图片</button>
        <button id="downloadBtn" disabled>下载结果</button>
        <button id="scaleBtn" disabled>归一化图片</button>

        <div class="canvas-container">
            <canvas id="previewCanvas"></canvas>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const imageInput = document.getElementById('imageInput');
            const jsonInput = document.getElementById('jsonInput');
            const widthInput = document.getElementById('widthInput');
            const heightInput = document.getElementById('heightInput');
            const processBtn = document.getElementById('processBtn');
            const scaleBtn = document.getElementById('scaleBtn');
            const downloadBtn = document.getElementById('downloadBtn');
            const canvas = document.getElementById('previewCanvas');
            const ctx = canvas.getContext('2d');

            let originalImage = null;
            let annotations = [];
            let scaleFactor = 1;

            // 检查是否已选择图片和JSON文件
            function checkInputs() {
                processBtn.disabled = !(originalImage && annotations.length > 0);
                downloadBtn.disabled = !(originalImage && annotations.length > 0);
                scaleBtn.disabled = !(originalImage && annotations.length > 0);
            }

            // 处理图片输入
            imageInput.addEventListener('change', function (e) {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = function (event) {
                        originalImage = new Image();
                        originalImage.onload = function () {
                            canvas.style.display = 'block';
                            drawImageWithAnnotations();
                            checkInputs();
                        };
                        originalImage.src = event.target.result;
                    };
                    reader.readAsDataURL(file);
                }
            });

            // 处理JSON输入
            jsonInput.addEventListener('change', function (e) {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = function (event) {
                        try {
                            annotations = JSON.parse(event.target.result);
                            if (originalImage) {
                                drawImageWithAnnotations();
                            }
                            checkInputs();
                        } catch (error) {
                            alert('解析JSON文件出错: ' + error.message);
                        }
                    };
                    reader.readAsText(file);
                }
            });

            // 绘制图片和标注
            function drawImageWithAnnotations() {
                if (!originalImage) return;

                const targetWidth = parseInt(widthInput.value);

                console.log(targetWidth, originalImage.width, originalImage.height)

                // 计算缩放比例
                scaleFactor = targetWidth / originalImage.width;

                // 设置canvas尺寸
                canvas.width = originalImage.width * scaleFactor;
                canvas.height = originalImage.height * scaleFactor;

                console.log("canvas", canvas.width, canvas.height);

                // 绘制图片
                ctx.drawImage(
                    originalImage,
                    0, 0, originalImage.width, originalImage.height, // 源图像区域
                    0, 0, originalImage.width * scaleFactor, originalImage.height * scaleFactor    // 目标区域（缩放后）
                );

                // 绘制标注
                ctx.strokeStyle = 'red';
                ctx.lineWidth = 2;
                ctx.font = '12px Arial';
                ctx.fillStyle = 'red';
                const colors = ['rgba(255,0,0,0.3)', 'rgba(0,255,0,0.3)', 'rgba(0,0,255,0.3)'];
                let targets = [];
                annotations.forEach((annotation, index) => {
                    const x = annotation.x;
                    const y = annotation.y;
                    const width = annotation.width;
                    const height = annotation.height;
                    console.log(y, canvas.height, y < canvas.height - 500)
                    if (y < canvas.height - 100 && annotation.char != " ") {
                        ctx.fillStyle = colors[index % colors.length];
                        ctx.strokeStyle = colors[index % colors.length];
                        // 绘制矩形
                        ctx.strokeRect(x, y, width, height);

                        // 绘制文字
                        if (annotation.char) {
                            ctx.fillText(annotation.char, x + 2, y + 12);
                        }
                        targets.push(annotation);
                    }
                });
                const randomDatas = createRandomOtherLabelData(targets, canvas.width, canvas.height - 100);
                ctx.fillStyle = 'red';
                ctx.strokeStyle = 'red';
                ctx.lineWidth = 4;
                randomDatas.forEach((annotation, index) => {
                    const x = annotation.x;
                    const y = annotation.y;
                    const width = annotation.width;
                    const height = annotation.height;
                    if (y < canvas.height - 100) {
                        // 绘制矩形
                        ctx.strokeRect(x, y, width, height);
                    }
                });

                setTimeout(() => {
                    // 转换并输出结果
                    // 假设图像宽度和高度（需要根据实际情况设置）
                    const imageWidth = canvas.width; // 示例值，请替换为实际图像宽度
                    const imageHeight = canvas.height; // 示例值，请替换为实际图像高度
                    const yoloAnnotationsFonts = toYoloFormat(targets, imageWidth, imageHeight, 1);
                    console.log(yoloAnnotationsFonts);
                    const yoloAnnotationsEmpty = toYoloFormat(randomDatas, imageWidth, imageHeight, 0);
                    console.log(yoloAnnotationsEmpty);
                }, 100)
            }

            function scaleImageAndDownload() {

                if (!originalImage) return;

                const targetWidth = parseInt(widthInput.value);

                // 计算缩放比例
                scaleFactor = targetWidth / originalImage.width;

                // console.log(targetWidth, originalImage.width, originalImage.height)

                const finalCanvas = document.createElement('canvas');
                // 设置canvas尺寸
                finalCanvas.width = originalImage.width * scaleFactor;
                finalCanvas.height = originalImage.height * scaleFactor;

                // console.log(finalCanvas.width, finalCanvas.height);

                const finalCtx = finalCanvas.getContext('2d');

                // 绘制图片
                finalCtx.drawImage(
                    originalImage,
                    0, 0, originalImage.width, originalImage.height, // 源图像区域
                    0, 0, finalCanvas.width, finalCanvas.height   // 目标区域（缩放后）
                );

                // 6. 触发下载
                const link = document.createElement('a');
                link.download = `scaled-screenshot-${Date.now()}.png`;
                link.href = finalCanvas.toDataURL('image/png');
                link.click();
            }

            /**
             * 检查两个矩形是否重叠
             */
            function isOverlapping(rect1, rect2) {
                return !(
                    rect1.x + rect1.width < rect2.x ||
                    rect2.x + rect2.width < rect1.x ||
                    rect1.y + rect1.height < rect2.y ||
                    rect2.y + rect2.height < rect1.y
                );
            }

            /**
             * 检查新矩形是否与任何现有矩形重叠
             */
            function hasAnyOverlap(newRect, existingRects) {
                return existingRects.some(rect => isOverlapping(newRect, rect));
            }

            /**
             * 生成随机整数
             */
            function getRandomInt(min, max) {
                return Math.floor(Math.random() * (max - min + 1)) + min;
            }

            /**
             * 生成随机浮点数
             */
            function getRandomFloat(min, max) {
                return Math.random() * (max - min) + min;
            }

            /**
             * 生成不重叠的新数据集
             */
            function generateNonOverlappingData(originalData, count, config) {
                const newData = [];
                const existingRects = [...originalData];

                for (let i = 0; i < count; i++) {
                    let attempts = 0;
                    let newRect;
                    let isValid = false;

                    while (attempts < config.maxAttempts && !isValid) {
                        // 生成随机宽度和高度
                        const width = getRandomFloat(config.minWidth, config.maxWidth);
                        const height = getRandomFloat(config.minHeight, config.maxHeight);

                        // 生成随机位置，确保不超过边界
                        const x = getRandomFloat(0, config.maxX - width);
                        const y = getRandomFloat(0, config.maxY - height);

                        newRect = {
                            char: " ", // 随机中文字符
                            x: x,
                            y: y,
                            width: width,
                            height: height
                        };

                        // 检查是否重叠
                        if (!hasAnyOverlap(newRect, existingRects)) {
                            isValid = true;
                            existingRects.push(newRect);
                            newData.push(newRect);
                        }

                        attempts++;
                    }

                    if (attempts >= config.maxAttempts) {
                        console.warn(`无法在第 ${i + 1} 个元素中找到不重叠的位置`);
                    }
                }

                return newData;
            }

            function createRandomOtherLabelData(targets, maxX, maxY) {
                // 配置参数
                const config = {
                    minWidth: 10,       // 最小宽度
                    maxWidth: 50,       // 最大宽度
                    minHeight: 10,      // 最小高度
                    maxHeight: 50,      // 最大高度
                    maxX: maxX,        // 最大X坐标（边界宽度）
                    maxY: maxY,        // 最大Y坐标（边界高度）
                    maxAttempts: 1000  // 最大尝试次数
                };
                const newData = generateNonOverlappingData(targets, targets.length, config);
                console.log(newData);
                return newData;
            }


            // 处理按钮点击
            processBtn.addEventListener('click', drawImageWithAnnotations);

            // 下载按钮点击
            downloadBtn.addEventListener('click', function () {
                // 转换为数据URL并下载
                const dataURL = canvas.toDataURL('image/png');
                const link = document.createElement('a');
                link.download = `annotated-image-${Date.now()}.png`;
                link.href = dataURL;
                link.click();
            });

            // 处理按钮点击
            scaleBtn.addEventListener('click', scaleImageAndDownload);

            // 尺寸输入变化时重新绘制
            widthInput.addEventListener('change', function () {
                if (originalImage && annotations.length > 0) {
                    drawImageWithAnnotations();
                }
            });

            heightInput.addEventListener('change', function () {
                if (originalImage && annotations.length > 0) {
                    drawImageWithAnnotations();
                }
            });
        });


        // 转换为YOLO格式
        function toYoloFormat(data, imgWidth, imgHeight, label) {

            return data.map(item => {
                // 计算中心点坐标和归一化
                const x_center = (item.x + item.width / 2) / imgWidth;
                const y_center = (item.y + item.height / 2) / imgHeight;

                // 计算归一化宽度和高度
                const norm_width = item.width / imgWidth;
                const norm_height = item.height / imgHeight;

                // YOLO格式：<class> <x_center> <y_center> <width> <height>
                // 这里假设字符"注"对应的类别是0（需要根据实际类别映射）
                return `${label} ${x_center.toFixed(6)} ${y_center.toFixed(6)} ${norm_width.toFixed(6)} ${norm_height.toFixed(6)}`;
            });
        }
    </script>
</body>

</html>